//
//  ZByteOperationsPrivate.h
//  Part of Z-Way.C library
//
//  Created by Pavel Kulaha.
//  Based on Z-Way source code written by Christian Paetz and Poltorak Serguei
//
//  Copyright (c) 2012 Z-Wave.Me
//  All rights reserved
//  info@z-wave.me
//
//  This source file is subject to the terms and conditions of the
//  Z-Wave.Me Software License Agreement which restricts the manner
//  in which it may be used.
//

#ifndef zbyte_operations_private_h
#define zbyte_operations_private_h

#include "ZPlatform.h"
#include "ZLog.h"
#include "ZByteOperations.h"

#if defined(__ESP32__)
#define ZNETWORK_HEADER_NAME_END ""
#else
#define ZNETWORK_HEADER_NAME_END ":"
#endif

#define ZNETWORK_HEADER_NAME_CONTENT_DISPOSITION "Content-Disposition" ZNETWORK_HEADER_NAME_END
#define ZNETWORK_HEADER_NAME_CONTENT_ENCODING "Content-Encoding" ZNETWORK_HEADER_NAME_END

typedef enum _ZByteDataTypeMemory_s
{
    _ZByteDataTypeMemoryStaticConst = 0,
    _ZByteDataTypeMemoryAllocatedByCaller,
    _ZByteDataTypeMemoryAllocated,
} _ZByteDataTypeMemory_t;

typedef struct _ZByteData_s
{
    ZWBYTE *buffer;
    size_t length;
    size_t maxlength;
    _ZByteDataTypeMemory_t type_memory:2;
} _ZByteData_t;

typedef struct _ZByteRingBuffer_s
{
    ZWLog log;
    ZWBYTE *buffer;
    size_t size;
    size_t head;
    size_t tail;
    size_t count;
} _ZByteRingBuffer_t;

static inline void _zbyte_data_init_allocated(_ZByteData_t *const data, void *const ptr, const size_t length, const size_t maxlength)
{
    data->buffer = (ZWBYTE *)ptr;
    data->length = length;
    data->maxlength = maxlength;
    data->type_memory = _ZByteDataTypeMemoryAllocated;
}
static inline void _zbyte_data_init_not_allocated(_ZByteData_t *const data, void *const ptr, const size_t length, const size_t maxlength)
{
    data->buffer = (ZWBYTE *)ptr;
    data->length = length;
    data->maxlength = maxlength;
    data->type_memory = _ZByteDataTypeMemoryAllocatedByCaller;
}
static inline void _zbyte_data_init_static_const(_ZByteData_t *const data, const void *const ptr, const size_t length, const size_t maxlength)
{
    data->buffer = (ZWBYTE *)ptr;
    data->length = length;
    data->maxlength = maxlength;
    data->type_memory = _ZByteDataTypeMemoryStaticConst;
}
ZWEXPORT_PRIVATE void _zbyte_data_init_static_const_str(_ZByteData_t *const data, const ZWCSTR str);
static inline void _zbyte_data_empty(_ZByteData_t *const data)
{
    (void)memset(data, 0, sizeof(_ZByteData_t)); // All variables should be zeroed unless explicitly set
    _zinit_null_ptr_after_memset_clear(&data->buffer);
}
ZWEXPORT_PRIVATE void _zbyte_data_free(_ZByteData_t *const data);
ZWEXPORT_PRIVATE ZWError _zbyte_data_dup(const _ZByteData_t *const src, _ZByteData_t *const dst);

ZWEXPORT_PRIVATE void _zbyte_ring_buffer_init(_ZByteRingBuffer_t *const ctx, const ZWLog log, void *const buffer, const size_t size);
ZWEXPORT_PRIVATE void _zbyte_ring_buffer_add_byte(_ZByteRingBuffer_t *const ctx, const ZWBYTE value);
ZWEXPORT_PRIVATE void _zbyte_ring_buffer_read_in_buffer(_ZByteRingBuffer_t *const ctx, void *const ptr, const size_t n);
ZWEXPORT_PRIVATE ZWBYTE _zbyte_ring_buffer_get_byte(_ZByteRingBuffer_t *const ctx);
static inline size_t _zbyte_ring_buffer_aviable(_ZByteRingBuffer_t *const ctx)
{
    return ctx->count;
};
static inline ZWBOOL _zbyte_ring_buffer_is_full(_ZByteRingBuffer_t *const ctx)
{
    return (ctx->count == ctx->size) ? TRUE : FALSE;
};

ZWEXPORT_PRIVATE ZWWORD _zbyte_crc16_ccitt_ext(const void *const ptr, const size_t length, ZWWORD crc);
static inline ZWWORD _zbyte_crc16_ccitt(const void *const ptr, const size_t length)
{
    return _zbyte_crc16_ccitt_ext(ptr, length, 0xFFFF);
}
static inline ZWWORD _zbyte_crc16_aug_ccitt_ext(const void *const ptr, const size_t length, ZWWORD crc)
{
    return _zbyte_crc16_ccitt_ext(ptr, length, crc);
}
static inline ZWWORD _zbyte_crc16_aug_ccitt(const void *const ptr, const size_t length)
{
    return _zbyte_crc16_aug_ccitt_ext(ptr, length, 0x1D0F);
}
ZWEXPORT_PRIVATE ZWDWORD _zbyte_crc32_zlib_ext(const void *const ptr, const size_t length, const ZWDWORD crc);
static inline ZWDWORD _zbyte_crc32_zlib(const void *const ptr, const size_t length)
{
    return _zbyte_crc32_zlib_ext(ptr, length, 0xFFFFFFFF) ^ 0xFFFFFFFF;
}

ZWEXPORT_PRIVATE ssize_t _zbinary_search(const void *arr, const void *find, size_t n, ssize_t (*cmp) (const void *arr, const void *find, size_t n));

ZWEXPORT_PRIVATE ZWSTR _zstring_concat(size_t *const p_output_length, ...);

typedef ZWDWORD _zhash_murmur_t;

ZWEXPORT_PRIVATE _zhash_murmur_t _zhash_murmur_calcul(const void *const data, const size_t length);

#define ZSTRING_JOIN(...) \
    zassert(_zstring_concat(NULL, __VA_ARGS__, NULL))

#define ZSTRING_JOIN_EXT(output_length, ...) \
    zassert(_zstring_concat(output_length, __VA_ARGS__, NULL))

static inline ZWBOOL _zstring_is_empty(const ZWCSTR str)
{
    return (str == NULL || str[0] == '\0');
}

#endif//zbyte_operations_private_h
